package cn.geminis.crypto.csp.soft.ec;

import cn.geminis.core.exception.CommonException;
import cn.geminis.core.util.FileUtils;
import cn.geminis.crypto.core.key.PrivateKey;
import cn.geminis.crypto.core.key.PublicKey;
import cn.geminis.crypto.csp.*;
import cn.geminis.crypto.csp.soft.SoftRandomGenerator;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;

import java.util.Arrays;

/**
 * @author Allen
 */
public class EcCspFactory extends AbstractCspFactory {

    private static final String PRIVATE_KEY_FILE_NAME = "ecPrivateKey.dat";
    private static final String PUBLIC_KEY_FILE_NAME = "ecPublicKey.dat";

    private final PrivateKey privateKey;
    private final PublicKey publicKey;
    private final byte[] mainKey;

    public EcCspFactory(String keyPath, String pin) {
        // 私钥加密密钥为口令的摘要值
        var digest = this.createDigest();
        var pinDigest = digest.digest(pin.getBytes());
        this.mainKey = Arrays.copyOf(pinDigest, 32);

        var cipher = this.createBlockCipher();

        var pkFileName = keyPath + PUBLIC_KEY_FILE_NAME;
        var skFileName = keyPath + PRIVATE_KEY_FILE_NAME;

        var pkData = FileUtils.readFile(pkFileName);
        var skData = FileUtils.readFile(skFileName);

        if (pkData == null || skData == null) {
            // 没有密钥，创建
            try (var generator = new EcKeyGenerator()) {
                var keypair = generator.generateKeyPair();
                pkData = keypair.getPublicKey().getEncoded();
                skData = keypair.getPrivateKey().getEncoded();

                skData = cipher.encrypt(skData);

                FileUtils.writeFile(pkFileName, pkData);
                FileUtils.writeFile(skFileName, skData);
            }
        }

        try {
            skData = cipher.decrypt(skData);
        } catch (Exception e) {
            throw new CommonException("解密PIN码保护的私钥错误", e);
        }

        this.privateKey = new PrivateKey(skData);
        this.publicKey = new PublicKey(pkData);

        register();
    }

    @Override
    public RandomGenerator createRandomGenerator() {
        return new SoftRandomGenerator();
    }

    @Override
    public String getDigestAlgOid() {
        return NISTObjectIdentifiers.id_sha256.toString();
    }

    @Override
    public String getDigestAlgName() {
        return "SHA-256";
    }

    @Override
    public AbstractDigest createDigest() {
        return new Sha256Digest();
    }

    @Override
    public String getSignerAlgOid() {
        return X9ObjectIdentifiers.ecdsa_with_SHA256.getId();
    }

    @Override
    public String getAsyncEncryptionAlgOid() {
        //TODO 更换为正确算法
        return NISTObjectIdentifiers.id_sha256.toString();
    }

    @Override
    public String getSignerAlgName() {
        return "Sha256WithECDSA";
    }

    @Override
    public AbstractSigner createSigner() {
        return new Sha256WithECSigner(publicKey, privateKey);
    }

    @Override
    public AbstractBlockCipher createBlockCipher() {
        return new AesBlockCipher(this.mainKey);
    }

    @Override
    public AbstractAsymmetricBlockCipher createAsymmetricBlockCipher() {
        return new EcBlockCipher(this.publicKey, this.privateKey);
    }

    @Override
    public KeyPairGenerator createKeyPairGenerator() {
        return new EcKeyGenerator();
    }

    @Override
    public AbstractAgreement createAgreement() {
        return new ECDHAgreement(this.publicKey, this.privateKey);
    }

    @Override
    public AbstractMac createMac() {
        return new Sha256HMac();
    }

    @Override
    public String getBlockCipherAlgOid() {
        //TODO 更换为正确算法
        return NISTObjectIdentifiers.id_hmacWithSHA3_256.toString();
    }

    @Override
    public String getKeyPairOid() {
        return X9ObjectIdentifiers.id_ecPublicKey.toString();
    }

    @Override
    public void close() {
        //nothing to close
    }
}
